/*
 * Copyright (C) 2007 Christian Laireiter <liree@web.de>
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms 
 * of the GNU General Public License as published by the Free Software Foundation; either 
 * version 2 of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied 
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along with 
 *  this program; if not, write to the Free Software Foundation, 
 *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 */
package mo.network.client.listeners;

import java.util.ArrayList;
import java.util.List;

import mo.network.server.data.Packet;


/**
 * @author Christian Laireiter
 */
public final class SenderEventQueue implements Runnable {
    /**
     * Logger for this class
     */
    
    private SenderEvent currentEvent;

    private Packet currentPacket;

    private final List<ISender> listeners;

    private final List<SenderEvent> packetEvent;

    private final List<Packet> queuedPackets;

    private boolean working = false;

    public SenderEventQueue() {
        this.queuedPackets = new ArrayList<Packet>();
        this.packetEvent = new ArrayList<SenderEvent>();
        this.listeners = new ArrayList<ISender>();
    }

    public void addISender(final ISender listener) {
        synchronized (this.listeners) {
            if (!this.listeners.contains(listener)) {
                this.listeners.add(listener);
            }
        }
    }

    /**
     * 
     */
    private void dequeue() {
        synchronized (this.queuedPackets) {
            this.currentPacket = null;
            if (!this.queuedPackets.isEmpty()) {
                this.currentPacket = this.queuedPackets.remove(0);
                this.currentEvent = this.packetEvent.remove(0);
            }
        }
    }

    public void enqueue(final Packet packet, final SenderEvent event) {
        synchronized (this.queuedPackets) {
            this.queuedPackets.add(packet);
            this.packetEvent.add(event);
            startWorker();
        }
    }

    public void removeISender(final ISender listener) {
        synchronized (this.listeners) {
            this.listeners.remove(listener);
        }
    }

    /**
     * (overridden)
     * 
     * @see java.lang.Runnable#run()
     */
    public void run() {
        synchronized (this.queuedPackets) {
            if (this.working) {
                return;
            }
            this.working = true;
        }
        dequeue();
        if (this.currentPacket != null) {
            synchronized (this.listeners) {
                for (final ISender current : this.listeners) {
                    try {
                        if (SenderEvent.PACKET_SENT.equals(this.currentEvent)) {
                            current.packetSent(this.currentPacket);
                        } else {
                            current.packetFailed(this.currentPacket);
                        }
                    } catch (final Throwable t) {
                        t.printStackTrace();
                    }
                }
            }
        }
        synchronized (this.queuedPackets) {
            this.working = false;
            startWorker();
        }
    }

    private void startWorker() {
        synchronized (this.queuedPackets) {
            if (!this.working && !this.queuedPackets.isEmpty()) {
                new Thread(this, "ISenderEventQueue").start();
            }
        }
    }

}
